package com.yummy.web.security.filter;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.yummy.web.security.config.SessionFilterProperties;
import com.yummy.web.security.context.RequestContext;
import com.yummy.web.security.context.Session;
import com.yummy.web.security.context.SessionManager;

public class SessionFilter extends AbstractSecurityFilter{
		
	private SessionManager sessionManager;
	
	private Logger logger = LoggerFactory.getLogger(getClass());

	public SessionFilter(SessionFilterProperties sessionFilterProperties,SessionManager sessionManager) {
		super(sessionFilterProperties);
		this.sessionManager = sessionManager;
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		try {
			initContext();
			if(!shouldFilter(request,response)) {
				chain.doFilter(request, response);
				return;
			}
			Session session = getOrCreateSession(request);
			saveSessionToContext(session);
			setResponse(response,session);
			chain.doFilter(request, response);
		} catch(Exception e) {
			throw e;
		} finally {
			touchSession();
			clearContext();
		}
	}

	private void setResponse(ServletResponse response, Session session) {
		HttpServletResponse httpResponse = (HttpServletResponse) response;
		httpResponse.setHeader(RequestContext.SESSION_KEY, session.getId());
	}

	private void touchSession() {
		Session session = RequestContext.getSession();
		if(session == null) {
			return;
		}
		session.touch();
		sessionManager.refresh(session);
	}

	private void saveSessionToContext(Session session) {
		RequestContext.setSession(session);
	}

	private Session getOrCreateSession(ServletRequest request) {
		String sessionid = getSessionId(request);
		if(sessionid == null) {
			logger.debug("cannot get sessionId , create one");
			return createSession();
		}
		Session session = getSession(sessionid);
		if(session == null) {
			logger.debug("cannot get session for sessionId = "+sessionid + ", create one");
			return createSession();
		}
		if(session.isExpired()) {
			logger.info("session is expired for sessionId = "+sessionid + ", create one");
			removeSession(session);
			return createSession();
		}
		if(!session.isValid()) {
			logger.error("session is invalid for sessionId = "+sessionid);
			return session;
		}
		return session;
	}

	private Session getSession(String sessionid) {
		return sessionManager.get(sessionid);
	}

	private String getSessionId(ServletRequest request) {
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		String sessionid = httpRequest.getHeader(RequestContext.SESSION_KEY);
		if(sessionid == null) {
			sessionid = httpRequest.getParameter(RequestContext.SESSION_KEY);
		}
		return sessionid;
	}

	private void removeSession(Session session) {
		sessionManager.remove(session.getId());
	}

	private Session createSession() {
		return sessionManager.create();
	}

	private void clearContext() {
		RequestContext.clear();
	}

	private void initContext() {
		RequestContext.clear();
	}

	@Override
	protected void sendAccessDenied(ServletRequest request, ServletResponse response) {
		
	}

	@Override
	protected boolean accessAllowed(ServletRequest request, ServletResponse response) {
		return true;
	}

}
